class Walk_list {
  int * list;
  int N_walk,N_list,DIM;
  void make_list_recurcive(ofstream & out_file,int * steps,int level,int *count,Table& table1);
 public:
  void read_walk(Walk&, int walk_num);                 // builds a walk from line walk_num in the list
  void dimerization(Walk&, int level,Table& table1);   // creats a walk by dimerization, level is the level of dimerization, table1 is a hash table, requires hash.h!!
  void dimerization(Walk&, int level,Table& table1,Log *log); //dimerization, logs acceptance rate and end to end distance
  void make_list(string filename,Table& table1);                     // creats a list of all self avoiding walks of length N_walk in DIM dimensions, saves list to a file named filename
  void make_list(string filename);
  void read_list(string,int n_list);                  // reads the list from a previously saved file, n_list is the number of walks in the file
  Walk_list(int n_walk, int d);
  ~Walk_list();
};

Walk_list::Walk_list(int n_walk,int d) {
  DIM=d;
  N_walk=n_walk;
  N_list=0;
  list=NULL;
}

Walk_list::~Walk_list() {
  delete [] list;
}

void Walk_list::make_list(string filename,Table& table1) {
  //Table table1(DIM,N_walk);
  const char * f_name = filename.c_str();
  int count=0;
  int * steps;
  steps = new int[N_walk];
  ofstream out_file;
  out_file.open(f_name);
  make_list_recurcive(out_file, steps, 0, & count ,table1);
  cout << "dimension: " << DIM << "\t length: " << N_walk << "\t number of walks: " <<   count << "\n";
  out_file.close();
  read_list(filename,count);
  delete [] steps;
}

void Walk_list::make_list(string filename) {
  Table table1(DIM,N_walk);
  const char * f_name = filename.c_str();
  int count=0;
  int * steps;
  steps = new int[N_walk];
  ofstream out_file;
  out_file.open(f_name);
  make_list_recurcive(out_file, steps, 0, & count ,table1);
  cout << "dimension: " << DIM << "\t length: " << N_walk << "\t number of walks: " <<   count << "\n";
  out_file.close();
  read_list(filename,count);
  delete [] steps;
}

void Walk_list::make_list_recurcive(ofstream & out_file,int * steps ,int level, int * count,Table& table1) {
  int i,j;
  if (level==N_walk) {
    Walk walk1(N_walk,DIM);
    walk1.read_steps(steps);
    if (walk1.check_SA(table1)) {
      walk1.print_steps(out_file);
      count[0]++;
    }
  }
    
  if (level<N_walk) {
    for (i=1;i<2*DIM+1;i++) {
      steps[level]=i;
      make_list_recurcive(out_file,steps,level+1,count,table1);
    }
  }
}

void Walk_list::read_list(string filename,int n_list) {
  char x;
  int i,step;
  ifstream in_file;
  const char * f_name;
  f_name=filename.c_str();
  in_file.open(f_name);
  N_list=n_list;
  list= new int[N_list*N_walk];
  in_file.seekg(0,ios::beg);
  for (i=0;i<N_list*N_walk;i++) {
    if (in_file.good()) {
	list[i]=in_file.get()-'0';
      }
    else {
      cout << "bad input file!\n";
      break;
    }
  }
}
    
void Walk_list::read_walk(Walk& walk, int walk_num) {
  int i;
  int * steps;
  steps= new int[N_walk];
  for (i=walk_num*N_walk;i<(walk_num+1)*N_walk;i++) {
    steps[i-walk_num*N_walk]=list[i];
  }
  walk.read_steps(steps);
  delete [] steps;
}

void Walk_list::dimerization(Walk& walk, int level,Table& table1) {
  int n;
  bool check;
  if (level==0) {
    n=ran2_int(&idum,0,N_list-1);
    if (n==N_list) n=0;
    read_walk(walk,n);
  }
  else {
    Walk walk1(pow(2,level-1)*N_walk,DIM);
    Walk walk2(pow(2,level-1)*N_walk,DIM);
    check=0;
    while (check==0) {
      dimerization(walk1,level-1,table1);
      dimerization(walk2,level-1,table1);
      walk.add_walks(walk1,walk2);
      check = walk.check_SA(table1);
    }
  }
}

void Walk_list::dimerization(Walk& walk, int level,Table& table1, Log *log) {
  int n;
  bool check;
  if (level==0) {
    n=ran2_int(&idum,0,N_list-1);
    if (n==N_list) n=0;
    read_walk(walk,n);
  }
  else {
    Walk walk1(pow(2,level-1)*N_walk,DIM);
    Walk walk2(pow(2,level-1)*N_walk,DIM);
    check=0;
    while (check==0) {
      log[level-1].att++;
      dimerization(walk1,level-1,table1,log);
      dimerization(walk2,level-1,table1,log);
      walk.add_walks(walk1,walk2);
      check = walk.check_SA(table1);
    }
    log[level-1].succ++; 
    log[level-1].R2=log[level-1].R2+walk.get_R_EE();
    log[level-1].R4=log[level-1].R4+walk.get_R_EE()*walk.get_R_EE();
  }
}
    
				 
    

    
  
    

    
  


